package display
{
	import builder.IRoomBuilder;
	
	import control.ControlBox;
	import control.controlBoxParts.IBoundsControlAware;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import mx.core.UIComponent;
	import mx.graphics.IStroke;
	import mx.graphics.SolidColorStroke;
	
	public class Room extends UIComponent implements IBoundsControlAware
	{
		private static const defautlStroke:IStroke = new SolidColorStroke(0, 2);
		
		private var _stroke:IStroke;
		
		private var _builder:IRoomBuilder;
		
		private var walls:Array;
		
		private var freeOperated:Boolean;
		
		private var controlBox:ControlBox;
		
		/**control之前原始的bounds*/
		private var controlInitBounds:Rectangle;
		
		private var controlInitLocation:Point;
		
		/**上一次的bounds*/
		private var controlOldBounds:Rectangle;
		
		private var controlBounds:Rectangle;
		
		private var _backgroundColor:Number;
		
	    public function Room()
		{
			super();
			this.addEventListener("freeLineEdited", onFreeEdited);
		}
		
		protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
		{
			while(this.numChildren)
			{
				this.removeChildAt(0);
			}
			if(!freeOperated)
			{			
				if(rbuilder)
				{
					walls = this.rbuilder.buildWalls(unscaledWidth, unscaledHeight, this.stroke);
				}
			}
			if(walls == null)
			{
				return;
			}
			if(freeOperated && controlOldBounds)
			{
				for(var i:int = 0; i < walls.length; i++)
				{
					Wall(walls[i]).scale(new Point(Math.round(isNaN(controlOldBounds.width)
					    ? controlInitBounds.width : controlOldBounds.width), Math.round(isNaN(controlOldBounds.height)
					     ? controlInitBounds.height : controlOldBounds.height)),
					    new Point(Math.round(unscaledWidth), Math.round(unscaledHeight)));
				}
				controlOldBounds = null;
				callLater(clearScaleTempData);
			}
			for(i = 0; i < walls.length; i++)
			{
				this.addChild(walls[i] as DisplayObject);
			}
			refresh();
		}
		
		public function paintBackgound():void
		{
			this.graphics.clear();
			if(isNaN(backgroundColor))
			{
				return;
			}
			var freelines:Array = this.freeLines;
			
			var totalLines:Array;
			for(var i:int = freelines.length - 1; i >= 0; i--)
			{
				var freeLine:FreeLine = freelines[i] as FreeLine;
				var lines:Array = freeLine.lines;
				if(totalLines == null)
				{
					totalLines = lines;
				}
				else if(lines.length > 0)
				{
					totalLines = totalLines.concat(lines);
				}
			}
			if(totalLines == null || totalLines.length <= 1)
			{
				return;
			}
			var index:int = totalLines.length - 1;
			this.graphics.beginFill(backgroundColor);
			var line:Line = totalLines[index];
			this.graphics.moveTo(line.pointOne.x, line.pointOne.y);
			this.graphics.lineTo(line.pointTwo.x, line.pointTwo.y);
			totalLines.splice(index, 1);
			var lastPoint:Point = line.pointTwo;
			while(totalLines.length > 0)
			{
				index = getLineAtPoint(totalLines, lastPoint);
				if(index < 0)
				{
					break;
				}
				line = totalLines[index];
				lastPoint  = line.pointOne != lastPoint ? line.pointOne : line.pointTwo;
				this.graphics.lineTo(lastPoint.x, lastPoint.y);
				totalLines.splice(index, 1);
			}
			this.graphics.endFill();
		}
		
		private function getLineAtPoint(lines:Array, point:Point):int
		{
			for(var i:int = lines.length - 1; i >= 0; i--)
			{
				var line:Line = lines[i] as Line;
				if(line.pointOne == point || line.pointTwo == point)
				{
				    return i;
				}
			}
			return -1;
		}
		
		public function refresh():void
		{
			if(!walls)
			{
				return;
			}
			var length:int = walls.length;
			for(var i:int = 0; i < length; i++)
			{
				Wall(walls[i]).refresh();
			}
			paintBackgound();
			this.dispatchEvent(new Event("locationChanged"));
		}
			
		/**
		 * 拆分room,生成新的room并返回
		 * @param position:bounds上对应的位置,如果为NaN,则默认是据中
		 */
		public function split(position:Number , direction:String = "horizontal"):Room
		{
			var bounds:Rectangle = this.getBounds(this.parent);
			if(isNaN(position))
			{
				position = direction == "horizontal" ? 
				    (bounds.x - this.x + bounds.width / 2) : 
				    (bounds.y - this.y + bounds.height / 2);
			}
			//1，把墙壁拆分
			var splitedWalls:Array = [];
			var newLine:FreeLine;
			var leftWalls:Array = [];
			var rightWalls:Array = [];			
			var points:Array = [];
			for(var i:int = walls.length - 1; i >= 0; i--)
			{
				var result:Object = Wall(walls[i]).split(position, direction);
				if(result is Array)
				{
					leftWalls.push(result[0]);
					rightWalls.push(result[1]);
					points.push(Wall(result[1]).freeLines[0].lines[0].pointOne);
					splitedWalls.push(walls[i]);
					continue;
				}
				//把lines分成两大阵营,1个阵营仍然呆在freeline中，另一个则放在splitedLine中
				if(result == "lt")
				{
					leftWalls.push(walls[i]);
				}
				else
				{
					rightWalls.push(walls[i]);
				}
			}
			if(splitedWalls.length <= 0)
			{
				return null;
			}
			if(points.length != 2)
			{
				return null;
			}					
			//2,在拆分点新建一堵墙
			
			var point_tl:Point  = points[0] as Point;
			var point_tr:Point= points[1] as Point;
			if(direction == "horizontal" && point_tl.y > point_tr.y)
			{
				var temp:Point = point_tr;
				point_tr = point_tl;
				point_tl = temp;
			}
			if (direction == "vertical" && point_tl.x > point_tr.x)
			{
				temp = point_tr;
				point_tr = point_tl;
				point_tl = temp;
			}
			var newWall:Wall = new Wall();
			var line:Line = new Line([point_tl, point_tr], stroke);
			var freeLine:FreeLine = new FreeLine();
			freeLine.lines = [line];
			newWall.freeLines = [freeLine];	
			
			//3,该room使用这堵墙
			leftWalls.push(newWall);
			this.walls = leftWalls;
			
			//4,新建room，使用这堵墙,分拆的墙	
			var newRoom:Room = new Room();
			newWall = new Wall();
			newWall.freeLines = [freeLine];
			rightWalls.push(newWall);
			newRoom.x = this.x;
			newRoom.y = this.y;
			newRoom.walls = rightWalls;
			newRoom.freeOperated = true;
			freeOperated = true;
			this.invalidateDisplayList();
			return newRoom;
		}
		
		/**
		 * 合并房间，并返回新的房间.
		 * 合并的房间必需是相邻的才行,换句话说有公共的freeline
		 */
		public function union(neighbor:Room):Room
		{
			//1,找到公共的freeLine		
			var neighborWalls:Array = neighbor.walls;
	    	var union:Boolean;
	    	for(var i:int = walls.length - 1; i >= 0; i--)
	    	{
	    		var wall:Wall = walls[i] as Wall;
	    		var wallLines:Array = wall.freeLines;
	    		for(var k:int = neighborWalls.length - 1; k >= 0; k--)
		    	{
		    		var neighborWall:Wall = neighborWalls[k] as Wall;
		    		var neighborLines:Array = neighborWall.freeLines;
		    		for(var lineIndex:int = neighborLines.length - 1; lineIndex >= 0; lineIndex--)
		    		{
		    			var neighborLine:FreeLine = neighborLines[lineIndex];
		    			var foundIndex:int = wallLines.indexOf(neighborLine);
		    			if(foundIndex >= 0)
		    			{
		    				wallLines.splice(foundIndex, 1);
		    				neighborLines.splice(lineIndex, 1);
		    				if(wallLines.length == 0)
		    				{
		    					walls.splice(i, 1);
		    				}
		    				if(neighborLines.length == 0)
		    				{
		    					neighborWalls.splice(k, 1);
		    				}
		    				union = true;
		    			}
		    		}
		    	}
	    	}
	    	if(!union)
	    	{
	    		return null;
	    	}
	    	walls = walls.concat(neighborWalls);
	    	this.invalidateDisplayList();
			//2,去掉freeLine
			
			//3,连接点
			
			//4,把neighbor的其他wall拿过来
			return this;
		}
		
		/**
		 * 返回选择的元素，可能有多个，比如在mode为MODE_SELECT_DETAIL的时候，有可能
		 * 选中多条线
		 * @see HouseArch.MODE_SELECT_DETAIL
		 */
		public function testSelect(mode:String, selecteRect:Rectangle):Array
		{
			if(mode == HouseArch.MODE_SELECT)
			{
				//形成一个矩形
				var bounds:Rectangle = this.getBounds(this.stage);
				trace("bounds: " + bounds);
				trace("selction : " + selecteRect);
				if(bounds.intersects(selecteRect))
				{
					return [this];
				}
			}
			else if(mode == HouseArch.MODE_EDIT_LINE)
			{
				
			}
			return null;
		}
		
		public function select():void
		{
			if(controlBox)
			{
				controlBox.clear();
			}
			controlInitLocation = new Point(this.x, this.y);
			controlInitBounds = this.getBounds(this.parent);
			controlBounds = controlInitBounds;
			//this.stroke = new  SolidColorStroke(0xff0000, 3);
            controlBox = new ControlBox(); 
            controlBox.setStyle("controlType", "size");
            controlBox.controlWidget = this;  
            controlBox.moveEnable = true;
            controlBox.liveSize = false;
		}
		
		/**
		 * 取消全部，不支持取消选中一部分
		 */
		public function deSelect():void
		{
			//this.stroke = defautlStroke;
			if(controlBox)
			{
				controlBox.clear();
				controlBox = null;
			}
		}
		
		public function boundsControled(bounds:Rectangle):void
		{
			if(controlBounds && bounds.width)
			{
				controlOldBounds = controlBounds;
			}
			this.x =  controlInitLocation.x + bounds.x - controlInitBounds.x;
			this.y = controlInitLocation.y + bounds.y - controlInitBounds.y;
			if(bounds.width)
			{
				this.width = bounds.width;
			}
			if(bounds.width)
			{
				this.height = bounds.height;
			}
			controlBounds = bounds;
			this.dispatchEvent(new Event("locationChanged"));
		}
		
		private function clearScaleTempData():void
		{
			Line.scaledPoints.length = 0;
		}

		public function get rbuilder():IRoomBuilder
		{
			return _builder;
		}

		public function set rbuilder(v:IRoomBuilder):void
		{
			_builder = v;
		}

		public function get stroke():IStroke
		{
			return _stroke ? _stroke : defautlStroke;
		}

		public function set stroke(v:IStroke):void
		{
			_stroke = v;
			for(var i:int = 0; i < walls.length; i++)
			{
				Wall(walls[i]).stroke = v;
			}
		}
		
		public function get freeLines():Array
		{
			var array:Array = [];
			for(var i:int = walls.length - 1; i >= 0; i--)
			{
				array = array.concat(Wall(walls[i]).freeLines);
			}
			return array;
		}
		
		private function onFreeEdited(event:Event):void
		{
			this.freeOperated = true;
		}
		
		public function set backgroundColor(v:Number):void
		{
			_backgroundColor = v;
			this.invalidateDisplayList();
		}
		
		public function get backgroundColor():Number
		{
			return _backgroundColor;
		}

        public function clear():void
        {
        	if(controlBox)
			{
				controlBox.clear();
			}
			controlBox = null;
        }

		
	}
}